<?php
include(join(DIRECTORY_SEPARATOR,array(dirname(__FILE__),'..','application','configs','env.php')));
include(join(DIRECTORY_SEPARATOR,array(dirname(__FILE__),'..','library','phplib.php')));

function getHeader($header)
{
	if (empty($header)) {
		require_once 'Zend/Controller/Request/Exception.php';
		throw new Zend_Controller_Request_Exception('An HTTP header name is required');
	}

	// Try to get it from the $_SERVER array first
	$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
	if (isset($_SERVER[$temp])) {
		return $_SERVER[$temp];
	}

	// This seems to be the only way to get the Authorization header on
	// Apache
	if (function_exists('apache_request_headers')) {
		$headers = apache_request_headers();
		if (isset($headers[$header])) {
			return $headers[$header];
		}
		$header = strtolower($header);
		foreach ($headers as $key => $value) {
			if (strtolower($key) == $header) {
				return $value;
			}
		}
	}

	return false;
}

$config = include(join(DIRECTORY_SEPARATOR,array(dirname(__FILE__),'..','application','configs','application.php')));
$secret = $config['secret_word'];

if (preg_match('~^.*?/(?P<hash>[0-9a-f]{32})/(?P<uri>.*)$~', $_SERVER['REQUEST_URI'], $info))
{
	if ($info['hash'] == md5($info['uri'].$secret))
	{
		if (getHeader('If-None-Match'))
		{
			header('HTTP/1.1 304 Not Modified', true, 304);
			exit();
		}

		$size  =   isset($_GET['size'])    ? $_GET['size']    : '0x0';
		$sharp =   isset($_GET['sharp'])   ? $_GET['sharp']   : null;
		$crop =    isset($_GET['crop'])    ? $_GET['crop']    : 0;
		$logo =    isset($_GET['logo'])    ? $_GET['logo']    : null;
		$format =  isset($_GET['format'])  ? $_GET['format']  : 'jpeg';
		$quality = isset($_GET['quality']) ? $_GET['quality'] : 95;
		$filter =  isset($_GET['filter'])  ? $_GET['filter']  : array();

		header("ETag: \"get-cached-image\"",true);
		$uri = preg_replace('~\\?.*$~','',$info['uri']);
		$object = new ImageConverter();
		$object->actionShow($uri, $size, $sharp, $crop, $filter, $logo, $format, $quality);
	}
	else
	{
		header('HTTP/1.1 403 Forbidden', true, 403);
		echo '<h1> Error: 403 Forbidden </h1>';
	}
}
else
{
	header('HTTP/1.1 404 Not Found', true, 404);
	echo '<h1> Error: 404 Not Found </h1>';
}

/**
 * Класс исключения.
 */
class CException extends Exception
{	
}

/**
 * Класс исключения, код которого устанавливается в качестве кода HTTP ответа.
 */
class CExceptionHttp extends CException
{
	protected $_httpCodes = array(
		404 => 'Not Found',
		500 => 'Internal Server Error',
	);
	
	public function __construct($message, $code)
	{
		header('HTTP/1.1 '.$code.($text = ' '.isset($this->_httpCodes[$code]) ? $this->_httpCodes[$code] : 'Unknown'),true,$code);
		echo '<h1>Error:'.$text.'</h1>';
		parent::__construct($message, $code);
	}
}

/**
 * Класс преобразования изображения.
 */
class ImageConverter
{
	/**
	 * @var array  Матрица увеличения резкости изображения.
	 */
	protected $_sharpMatrix = array(
		array(-1, -2, -1),
		array(-2, 24, -2),
		array(-1, -2, -1),
	);

	/**
	 * @var integer  Нормализатор матрицы резкости.
	 */
	protected $_sharpDiv = 12;

	/**
	 * @var integer  Смещение цвета при увеличении резкости.
	 */
	protected $_sharpOffset = 0;

	/**
	 * Чтение контента по его URI.
	 * 
	 * @param string $uri
	 * @throws CException
	 */
	protected function _loadUriContent($uri)
	{
		$uri = ltrim($uri,'/');

		if (file_exists($_SERVER['DOCUMENT_ROOT'].'/'.$uri))
		{
			return file_get_contents($_SERVER['DOCUMENT_ROOT'].'/'.$uri);
		}
		elseif (file_exists($uri))
		{
			return file_get_contents($uri);
		}

		throw new CExceptionHttp('File was not find on server.', 404);
	}

	/**
	 * Отображение изображения, приведённого к заданным параметрам.
	 * 
	 * @param string $uri  Путь к изображению относительно DOCUMENT_ROOT.
	 * @param string $size OPTIONAL  Размеры области, в которую вписывается изображение.
	 * @param integer $sharp OPTIONAL  Включение резкости и задание уровня этой резкости. 
	 * @param boolean $crop OPTIONAL  Флаг отрезания части изображения для его полного вписания в заданную область.
	 * @param array $filter OPTIONAL  Список применяемых фильтров.
	 * @param array $logo OPTIONAL  Пути к логотипам, которые будут наложенны на изображение.
	 * @param string $format OPTIONAL  Формат итогового изображения.
	 * @param integer $quality OPTIONAL  Процент качества JPEG изображения.
	 */
	public function actionShow($uri, $size = null, $sharp = null, $crop = null, $filter = null, $logo = null, $format = 'jpeg', $quality = 90)
	{
		// Чтение файла изображения в строку.
		$source = $this->_loadUriContent($uri);

		// Создание ресурса исходного изображения и получения его параметров.
		if (!$source = @imagecreatefromstring($source))
		{
			throw new CExceptionHttp('Wrong image file at '.$uri, 500);
		}

		$srcWidth  = $targetWidth  = imagesx($source);
		$srcHeight = $targetHeight = imagesy($source);
		$target = $coofOriginal = 0;

		// Анализ и обработка параметров.
		list($width, $height) = explode('x', isset($size) ? $size : '0x0', 2);
		$width  = empty($width)  ? $srcWidth  : (int)$width;
		$height = empty($height) ? $srcHeight : (int)$height;
		$crop = empty($crop) ? 0 : (int)$crop;
		$sharp = isset($sharp) ? max(0, (int)$sharp) : 20;

		// Расчёт новых размеров изображения.
		while (TRUE):
			$coof = $crop ? max($width / $srcWidth, $height / $srcHeight) : min($width / $srcWidth, $height / $srcHeight);
			empty($coofOriginal) && $coofOriginal = $coof;
			$targetWidth  = $crop ? $width : round($srcWidth * $coof);
			$targetHeight = $crop ? $height : round($srcHeight * $coof);
			$copyWidth  = $crop ? min(round($targetWidth  / $coof), $srcWidth)  : $srcWidth;
			$copyHeight = $crop ? min(round($targetHeight / $coof), $srcHeight) : $srcHeight;
			$deltaCoof = array(0, 1, 0.32, 0, 1.68, 2);
			$deltaX = $crop ? round(($srcWidth  - $copyWidth)  / 2 * $deltaCoof[$crop]) : 0;
			$deltaY = $crop ? round(($srcHeight - $copyHeight) / 2 * $deltaCoof[$crop]) : 0;

			// Изменение размеров изображения.
			if ($targetWidth * 2 < $srcWidth)
			{
				$target = imagecreatetruecolor($srcWidth >> 1, $srcHeight >> 1);
				imagecopyresampled($target, $source, 0, 0, 0, 0, $srcWidth >> 1, $srcHeight >> 1, $srcWidth, $srcHeight);
				imagedestroy($source);
				$source = $target;
				$srcWidth = imagesx($source);
				$srcHeight = imagesy($source);
				continue;
			}
			else
			{
				$target = imagecreatetruecolor($targetWidth, $targetHeight);
				imagecopyresampled($target, $source, 0, 0, $deltaX, $deltaY, $targetWidth, $targetHeight, $copyWidth, $copyHeight);
				break;
			}
		endwhile;
		
		// Повышение резкости изображения.
		if ($coofOriginal < 1 && $coofOriginal > 0 && $sharp > 0)
		{
			$matrix = $this->_sharpMatrix;
			$matrix[1][1] += round($sharp * $coofOriginal);
			//imageconvolution($target, $matrix, $matrix[1][1] - $this->_sharpDiv, $this->_sharpOffset);
		}

		// Применение фильтров.
		foreach ((array)$filter as $name)
		{
			if (function_exists('imagefilter'))
			{
				switch ($name)
				{
					case 'grayscale':
						imagefilter($target, IMG_FILTER_GRAYSCALE);
						break;
				}
			}
		}
		
		// Наложение логотипов.
		if (isset($logo))
		{
			foreach ((array)$logo as $logotype)
			{
				list($type, $uri) = explode(',', $logotype, 2);

				// Загрузка изображения логотипа.
				try
				{
					$logosource = $this->_loadUriContent($uri);
				}
				catch (CException $exception)
				{
					continue;
				}

				if (!$logosource = @imagecreatefromstring($logosource))
				{
					continue;
				}

				// Получение размеров логотипа и проверка того, что логотип вписывается в изображение.
				$logoWidth = imagesx($logosource);
				$logoHeight = imagesy($logosource);

				if ($logoWidth > $targetWidth || $logoHeight > $targetHeight)
				{
					continue;
				}

				// Наложение логотипа в шахматном порядке.
				if ($type == 0)
				{
					$widthCnt = floor($targetWidth / $logoWidth);
					$heightCnt = floor($targetHeight / $logoHeight);

					if ($widthCnt > 1 && $heightCnt > 1)
					{
						for ($y = 0; $y < $heightCnt; $y++)
						{
							for ($x = 0; $x < $widthCnt; $x++)
							{
								if ($x % 2 !== $y % 2)
								{
									continue;
								}

								$dst_x = round(($x * 2 + 1) * ($targetWidth / ($widthCnt * 2)) - $logoWidth / 2);
								$dst_y = round(($y * 2 + 1) * ($targetHeight / ($heightCnt * 2)) - $logoHeight / 2);
								imagecopy($target, $logosource, $dst_x, $dst_y, 0, 0, $logoWidth, $logoHeight);
							}
						}

						continue;
					}

					$type = 1;
				}

				// Выбор из простых расположений логотипа.
				$marginCoof = 0.05;
				$dst_x = $dst_y = 0;

				switch ($type)
				{
					case 1: // center
					case 8: // top
					case 9: // bottom
						$dst_x = round(($targetWidth - $logoWidth) / 2);
						break;

					case 2: // left-top
					case 3: // left-bottom
					case 6: // left
						$dst_x = round(0 + ($targetWidth - $logoWidth) * $marginCoof);
						break;

					case 4: // right-top
					case 5: // right-bottom
					case 7: // right
						$dst_x = round($targetWidth - $logoWidth - ($targetWidth - $logoWidth) * $marginCoof);
						break;
				}

				switch ($type)
				{
					case 1: // center
					case 6: // left
					case 7: // right
						$dst_y = round(($targetHeight - $logoHeight) / 2);
						break;

					case 2: // left-top
					case 4: // right-top
					case 8: // top
						$dst_y = round(0 + ($targetHeight - $logoHeight) * $marginCoof);
						break;

					case 3: // left-bottom
					case 5: // right-bottom
					case 9: // bottom
						$dst_y = round($targetHeight - $logoHeight - ($targetHeight - $logoHeight) * $marginCoof);
						break;
				}

				imagecopy($target, $logosource, $dst_x, $dst_y, 0, 0, $logoWidth, $logoHeight);
			}
		}

		// Сохранение и вывод изображения.
		header('Content-Type: image/'.$format, true);
		$format == 'jpeg' ? imagejpeg($target, null, $quality) : imagepng($target);
	}
}
?>